<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="Kjags" id="Kjags"><span data-lake-id="u0dd8c5b1" id="u0dd8c5b1">典型回答</span></h1>
  <p data-lake-id="ue813d216" id="ue813d216"><span data-lake-id="u9b6b0873" id="u9b6b0873">​</span><br></p>
  <p data-lake-id="u7785b875" id="u7785b875"><span data-lake-id="udf993ad2" id="udf993ad2">有的时候，我们加了索引，也不一定最终查询语句就能用上索引，因为Innodb要不要使用索引，该使用哪个索引是优化器决定的，它是根据成本（代价）预估来选择的，他会倾向于选择一个成本最低的方式进行查询。</span></p>
  <p data-lake-id="u5ded3f38" id="u5ded3f38"><span data-lake-id="u7274b472" id="u7274b472">​</span><br></p>
  <p data-lake-id="ucfd247f4" id="ucfd247f4"><span data-lake-id="uaa303c6f" id="uaa303c6f">那么这个所谓的代价，或者叫做成本，都和什么有关的，主要是以下几个因素：</span></p>
  <p data-lake-id="ue138e8ef" id="ue138e8ef"><span data-lake-id="u06f9e861" id="u06f9e861">​</span><br></p>
  <ol list="ucb0d6c54">
   <li fid="u4aeb3826" data-lake-id="u403b4119" id="u403b4119"><strong><span data-lake-id="u72dbd67e" id="u72dbd67e">基数性（Cardinality）</span></strong><span data-lake-id="u3b481f0e" id="u3b481f0e">：</span></li>
  </ol>
  <ul list="u4bd61740" data-lake-indent="1">
   <li fid="udd91a33f" data-lake-id="u991b31f3" id="u991b31f3"><span data-lake-id="uf083d2e7" id="uf083d2e7">索引的基数性其实</span><strong><span data-lake-id="u081dbf31" id="u081dbf31">就是我们通常说的区分度</span></strong><span data-lake-id="u7d3688b5" id="u7d3688b5">，表示索引中不同值的数量。基数性越高，索引区分度越好，优化器越倾向于使用该索引。</span></li>
   <li fid="udd91a33f" data-lake-id="u1b03c166" id="u1b03c166"><span data-lake-id="u23db514f" id="u23db514f">参考：</span><a href="https://www.mysqltutorial.org/mysql-index/mysql-index-cardinality/" target="_blank" data-lake-id="ue7a1de7a" id="ue7a1de7a"><span data-lake-id="u2a35eb8b" id="u2a35eb8b">https://www.mysqltutorial.org/mysql-index/mysql-index-cardinality/</span></a></li>
  </ul>
  <ol list="ucb0d6c54" start="2">
   <li fid="u4aeb3826" data-lake-id="u92c155ee" id="u92c155ee"><strong><span data-lake-id="u5a27e9d3" id="u5a27e9d3">选择性（Selectivity）</span></strong><span data-lake-id="u736cee95" id="u736cee95">：</span></li>
  </ol>
  <ul list="uf1de4e1e" data-lake-indent="1">
   <li fid="u02116c18" data-lake-id="ub612c6fa" id="ub612c6fa"><span data-lake-id="u3ff3862f" id="u3ff3862f">选择性是指索引过滤数据的能力。高选择性意味着索引能过滤掉更多的行，优化器会偏向于使用这样的索引。</span></li>
   <li fid="u02116c18" data-lake-id="u7c85a5c0" id="u7c85a5c0"><span data-lake-id="ub50c9641" id="ub50c9641">这个因素是决定着扫描行数的关键。同一个查询语句，选择性更高的索引会使得扫描行数更少。</span></li>
  </ul>
  <ol list="ucb0d6c54" start="3">
   <li fid="u4aeb3826" data-lake-id="ub706d154" id="ub706d154"><strong><span data-lake-id="ua189aa76" id="ua189aa76">索引覆盖</span></strong><span data-lake-id="u8b2be7d3" id="u8b2be7d3">：</span></li>
  </ol>
  <ul list="u84e5b398" data-lake-indent="1">
   <li fid="ufeb11d15" data-lake-id="ud13bd4c5" id="ud13bd4c5"><span data-lake-id="uc7e6d32e" id="uc7e6d32e">如果一个查询可以完全通过索引来解决，即所需的所有列都包含在索引中，优化器会倾向于使用这样的“覆盖索引”。</span></li>
  </ul>
  <ol list="ucb0d6c54" start="4">
   <li fid="u4aeb3826" data-lake-id="u058ed058" id="u058ed058"><strong><span data-lake-id="udb28aea5" id="udb28aea5">ORDER BY:</span></strong></li>
  </ol>
  <ul list="u4362a013" data-lake-indent="1">
   <li fid="ufeb11d15" data-lake-id="ucadb29dd" id="ucadb29dd"><span data-lake-id="uffbc0dd7" id="uffbc0dd7">为了避免额外的排序操作，当SQL语句中有ORDER BY时，如果这个字段有索引，那么优化器为了减少file sort，会愿意选择使用这个索引，因为索引天然有序。</span></li>
  </ul>
  <ol list="ucb0d6c54" start="5">
   <li fid="u4aeb3826" data-lake-id="ue3d59c0c" id="ue3d59c0c"><span data-lake-id="u5b93b3c4" id="u5b93b3c4">索引类型</span><span data-lake-id="uc9692c53" id="uc9692c53">：</span></li>
  </ol>
  <ul list="uefbf949f" data-lake-indent="1">
   <li fid="u6f86945b" data-lake-id="ue2cca76c" id="ue2cca76c"><span data-lake-id="u71cf714c" id="u71cf714c">不同类型的索引（如B-TREE、HASH、FULLTEXT等）适用于不同类型的查询。优化器会根据查询类型选择最合适的索引。</span></li>
  </ul>
  <ol list="ucb0d6c54" start="6">
   <li fid="u4aeb3826" data-lake-id="ua81dbac5" id="ua81dbac5"><span data-lake-id="ueedd77e3" id="ueedd77e3">JOIN类型和顺序</span><span data-lake-id="ud529ad53" id="ud529ad53">：</span></li>
  </ol>
  <ul list="u651cb4b8" data-lake-indent="1">
   <li fid="u38f93d50" data-lake-id="uceb50d13" id="uceb50d13"><span data-lake-id="u829d811c" id="u829d811c">对于包含JOIN的查询，优化器会考虑使用哪些索引以及JOIN的顺序。</span></li>
  </ul>
  <ol list="ucb0d6c54" start="7">
   <li fid="u4aeb3826" data-lake-id="ubc8e8a14" id="ubc8e8a14"><span data-lake-id="u172ac6c4" id="u172ac6c4">索引的大小和深度</span><span data-lake-id="u2e677b32" id="u2e677b32">：</span></li>
  </ol>
  <ul list="u8cc116d9" data-lake-indent="1">
   <li fid="ue6e5a02b" data-lake-id="u0c5b27ec" id="u0c5b27ec"><span data-lake-id="ufee9ce3b" id="ufee9ce3b">较小、较浅的索引通常更快，因为它们占用更少的磁盘空间，可以更快地加载到内存中。</span></li>
  </ul>
  <ol list="ucb0d6c54" start="8">
   <li fid="u4aeb3826" data-lake-id="u9b010598" id="u9b010598"><span data-lake-id="u17d2c53e" id="u17d2c53e">访问类型</span><span data-lake-id="uf16be132" id="uf16be132">：</span></li>
  </ol>
  <ul list="ud5362195" data-lake-indent="1">
   <li fid="u65092bd2" data-lake-id="ueba293e7" id="ueba293e7"><span data-lake-id="ud059b8b4" id="ud059b8b4">访问类型，如范围查询、点查找、扫描等，也会影响索引的选择。例如，某些索引可能更适合范围查询。</span></li>
  </ul>
  <ol list="ucb0d6c54" start="9">
   <li fid="u4aeb3826" data-lake-id="u01fb682d" id="u01fb682d"><span data-lake-id="uab9c5aaa" id="uab9c5aaa">内存使用</span><span data-lake-id="u4c3f93ba" id="u4c3f93ba">：</span></li>
  </ol>
  <ul list="u1f2518bc" data-lake-indent="1">
   <li fid="u59ec9c4b" data-lake-id="uda1f03af" id="uda1f03af"><span data-lake-id="u944a8afb" id="u944a8afb">对于大型表，优化器还会考虑执行计划的内存使用情况，尽量避免造成过多的内存占用。</span></li>
  </ul>
  <ol list="ucb0d6c54" start="10">
   <li fid="u4aeb3826" data-lake-id="u5f8e2404" id="u5f8e2404"><span data-lake-id="uee65f32b" id="uee65f32b">系统资源限制</span><span data-lake-id="ucd214d11" id="ucd214d11">：</span></li>
  </ol>
  <ul list="u122eb90e" data-lake-indent="1">
   <li fid="u5acbdd1c" data-lake-id="ubdbbd4e4" id="ubdbbd4e4"><span data-lake-id="uf1e2b70f" id="uf1e2b70f">优化器还会考虑系统的资源限制，如内存和磁盘I/O。</span></li>
  </ul>
  <ol list="ucb0d6c54" start="11">
   <li fid="u4aeb3826" data-lake-id="u1a7c2e20" id="u1a7c2e20"><span data-lake-id="ue4b2024e" id="ue4b2024e">查询缓存</span><span data-lake-id="u60941e98" id="u60941e98">：</span></li>
  </ol>
  <ul list="ua240bb04" data-lake-indent="1">
   <li fid="u7c22dccb" data-lake-id="u45cb44f3" id="u45cb44f3"><span data-lake-id="u873a8a62" id="u873a8a62">如果启用了查询缓存且相同的查询已被缓存，优化器会使用这个缓存的结果而不是选择新的索引。</span></li>
  </ul>
  <p data-lake-id="ua146862c" id="ua146862c"><span data-lake-id="ud853df5c" id="ud853df5c"><br></span><strong><span data-lake-id="ua3c1e0ee" id="ua3c1e0ee">这里面比较重要的因素就是索引的基数性（区分度）、索引的选择性（扫描行数）、是否有索引覆盖等这几个。</span></strong></p>
  <p data-lake-id="u9f5fc9b4" id="u9f5fc9b4"><strong><span data-lake-id="u8f5f4e90" id="u8f5f4e90">​</span></strong><br></p>
  <p data-lake-id="u55f3c4e2" id="u55f3c4e2"><span data-lake-id="u80623fb1" id="u80623fb1">因为如何选择索引是由以上这些因素共同决定的，所以最终选错了索引，可能有以下几个原因：</span></p>
  <p data-lake-id="udd20890f" id="udd20890f"><span data-lake-id="u2a38364b" id="u2a38364b">​</span><br></p>
  <ol list="udab5c91e">
   <li fid="u5ea14434" data-lake-id="ue1c8300c" id="ue1c8300c"><strong><span data-lake-id="uce2cee5c" id="uce2cee5c">不准确的统计信息</span></strong><span data-lake-id="u4518ab82" id="u4518ab82">：</span></li>
  </ol>
  <ul list="u4852f20d" data-lake-indent="1">
   <li fid="ue96f0918" data-lake-id="u4116dd97" id="u4116dd97"><span data-lake-id="ua331d88c" id="ua331d88c">InnoDB存储引擎依赖统计信息来决定使用哪个索引，如基数性、选择性这些都是统计信息。如果这些统计信息过时或不准确，优化器可能做出错误的决策。</span></li>
  </ul>
  <ol list="udab5c91e" start="2">
   <li fid="u5ea14434" data-lake-id="u15c2391b" id="u15c2391b"><span data-lake-id="u6f86dd49" id="u6f86dd49">复杂的查询逻辑</span><span data-lake-id="ub0347a50" id="ub0347a50">：</span></li>
  </ol>
  <ul list="u2401aa07" data-lake-indent="1">
   <li fid="u255e15df" data-lake-id="u738393de" id="u738393de"><span data-lake-id="u6a637183" id="u6a637183">对于复杂的查询，尤其是那些包含多表join、子查询、函数等的查询，优化器可能难以准确判断哪个索引最有效。</span></li>
  </ul>
  <ol list="udab5c91e" start="3">
   <li fid="u5ea14434" data-lake-id="u3dc25e76" id="u3dc25e76"><span data-lake-id="udd532e89" id="udd532e89">系统和配置因素</span><span data-lake-id="u49720ffb" id="u49720ffb">：</span></li>
  </ol>
  <ul list="ue0eddae3" data-lake-indent="1">
   <li fid="ud8e6373f" data-lake-id="ucdc184af" id="ucdc184af"><span data-lake-id="ufe61f5a8" id="ufe61f5a8">MySQL的配置设置和系统资源限制（如内存大小）也会影响优化器的决策。</span></li>
  </ul>
  <p data-lake-id="u5ff4196c" id="u5ff4196c"><br></p>
  <p data-lake-id="ubbbcbc72" id="ubbbcbc72"><span data-lake-id="u5baf33bf" id="u5baf33bf">那么，如果发现mysql选择了一个错误的索引，一般来说有以下几种解决方式：</span></p>
  <p data-lake-id="u8384efb6" id="u8384efb6"><br></p>
  <ol list="u9b5c058f">
   <li fid="u318f8ba7" data-lake-id="u0c21799f" id="u0c21799f"><strong><span data-lake-id="ud660219b" id="ud660219b">更新统计信息</span></strong><span data-lake-id="ua0e514ab" id="ua0e514ab">：</span></li>
  </ol>
  <ul list="u5bb39747" data-lake-indent="1">
   <li fid="uaf0ef564" data-lake-id="u1b9f5ab8" id="u1b9f5ab8"><span data-lake-id="u77f4f703" id="u77f4f703">定期运行</span><span data-lake-id="u30ea3461" id="u30ea3461">ANALYZE TABLE</span><span data-lake-id="ufd5e03bd" id="ufd5e03bd">命令来更新表的统计信息。这可以帮助优化器更准确地评估各个索引的有效性。</span></li>
  </ul>
  <ol list="u9b5c058f" start="2">
   <li fid="u318f8ba7" data-lake-id="u753a5fbd" id="u753a5fbd"><strong><span data-lake-id="u50790387" id="u50790387">使用强制索引（FORCE INDEX）</span></strong><span data-lake-id="u75c77984" id="u75c77984">：</span></li>
  </ol>
  <ul list="ua5e3e119" data-lake-indent="1">
   <li fid="ue6851109" data-lake-id="u7a74fd4b" id="u7a74fd4b"><span data-lake-id="uf19c3789" id="uf19c3789">如果我们确定某个索引比优化器选择的更有效，可以在查询中使用FORCE INDEX来强制使用特定索引。</span></li>
   <li fid="ue6851109" data-lake-id="ue2c00aba" id="ue2c00aba"><span data-lake-id="uecc6d84e" id="uecc6d84e">如</span><code data-lake-id="uaa8971ea" id="uaa8971ea"><span data-lake-id="u44481509" id="u44481509">SELECT * FROM hollis_test_table FORCE INDEX (idx_name) WHERE name ='Hollis';</span></code></li>
   <li fid="ue6851109" data-lake-id="u6f9ce7e1" id="u6f9ce7e1"><span data-lake-id="ud1284d4e" id="ud1284d4e" style="color: #DF2A3F">但是，FORCE INDEX 应该谨慎使用，</span><span data-lake-id="uba35cdf1" id="uba35cdf1">因为</span><strong><span data-lake-id="ua8272ed6" id="ua8272ed6">强制使用特定的索引可能会导致性能下降，特别是当表的数据分布发生变化时。</span></strong><span data-lake-id="u5bf51e0a" id="u5bf51e0a">在使用之前，应该确保理解该索引为什么是最好的选择，并且定期评估其效果。</span></li>
  </ul>
  <ol list="u9b5c058f" start="3">
   <li fid="u318f8ba7" data-lake-id="u5d1bde5f" id="u5d1bde5f"><span data-lake-id="ud156d87f" id="ud156d87f">优化查询</span><span data-lake-id="uaaf1b07d" id="uaaf1b07d">：</span></li>
  </ol>
  <ul list="uce5a9a6b" data-lake-indent="1">
   <li fid="uc78d065c" data-lake-id="ucd24ea4c" id="ucd24ea4c"><span data-lake-id="u2fb85496" id="u2fb85496">简化查询逻辑，尽量避免复杂的连接和子查询，这有助于优化器做出更好的决策。</span></li>
  </ul>
  <ol list="u9b5c058f" start="4">
   <li fid="u318f8ba7" data-lake-id="u211f71df" id="u211f71df"><span data-lake-id="ud05ee44d" id="ud05ee44d">调整索引：</span></li>
  </ol>
  <ul list="u17c18c78" data-lake-indent="1">
   <li fid="u1ab15012" data-lake-id="u1fe62b61" id="u1fe62b61"><span data-lake-id="u0150b23a" id="u0150b23a">我们可以为where条件中的过滤条件创建更合适的索引，并尽可能考虑创建复合索引来提高查询效率，尤其是对于多列的过滤和排序。</span></li>
  </ul>
  <ol list="u9b5c058f" start="5">
   <li fid="u318f8ba7" data-lake-id="u12d764cd" id="u12d764cd"><span data-lake-id="uf0230b5d" id="uf0230b5d">调整MySQL配置</span><span data-lake-id="u48bcc8fa" id="u48bcc8fa">：</span></li>
  </ol>
  <ul list="ue454673d" data-lake-indent="1">
   <li fid="ue3225a9b" data-lake-id="u0da2d760" id="u0da2d760"><span data-lake-id="ub984637f" id="ub984637f">根据系统的资源和需求调整MySQL的配置参数，比如缓冲池大小（innodb_buffer_pool_size）。</span></li>
  </ul>
 </body>
</html>